home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 243_01 / cpp5.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-12  |  31.4 KB  |  1,032 lines

  1.  
  2. /*
  3.  *                          C P P 5 . C
  4.  *              E x p r e s s i o n   E v a l u a t i o n
  5.  *
  6.  * Edit History
  7.  * 31-Aug-84    MM      USENET net.sources release
  8.  * 04-Oct-84    MM      __LINE__ and __FILE__ must call ungetstring()
  9.  *                      so they work correctly with token concatenation.
  10.  *                      Added string formal recognition.
  11.  * 25-Oct-84    MM      "Short-circuit" evaluate #if's so that we
  12.  *                      don't print unnecessary error messages for
  13.  *                      #if !defined(FOO) && FOO != 0 && 10 / FOO ...
  14.  * 31-Oct-84    ado/MM  Added token concatenation
  15.  *  6-Nov-84    MM      Split from #define stuff, added sizeof stuff
  16.  * 19-Nov-84    ado     #if error returns TRUE for (sigh) compatibility
  17.  * 22-Apr-85    ado/MM  added evalone to properly handle \value
  18.  * 29-Apr-85    ado     Cleaned up #if ... sizeof
  19.  */
  20.  
  21. #include        "cppdef.h"
  22. #include        "cpp.h"
  23.  
  24. /*
  25.  * Evaluate an #if expression.
  26.  */
  27.  
  28. static char     *opname[] = {           /* For debug and error messages */
  29. "end of expression", "val", "id",
  30.   "+",   "-",  "*",  "/",  "%",
  31.   "<<", ">>",  "&",  "|",  "^",
  32.   "==", "!=",  "<", "<=", ">=",  ">",
  33.   "&&", "||",  "?",  ":",  ",",
  34.   "unary +", "unary -", "~", "!",  "(",  ")", "(none)",
  35. };
  36.  
  37. /*
  38.  * opdope[] has the operator precedence:
  39.  *     Bits
  40.  *        7     Unused (so the value is always positive)
  41.  *      6-2     Precedence (000x .. 017x)
  42.  *      1-0     Binary op. flags:
  43.  *          01  The binop flag should be set/cleared when this op is seen.
  44.  *          10  The new value of the binop flag.
  45.  * Note:  Expected, New binop
  46.  * constant     0       1       Binop, end, or ) should follow constants
  47.  * End of line  1       0       End may not be preceeded by an operator
  48.  * binary       1       0       Binary op follows a value, value follows.
  49.  * unary        0       0       Unary op doesn't follow a value, value follows
  50.  *   (          0       0       Doesn't follow value, value or unop follows
  51.  *   )          1       1       Follows value.  Op follows.
  52.  */
  53.  
  54. static char     opdope[OP_MAX] = {
  55.   0001,                                 /* End of expression            */
  56.   0002,                                 /* Digit                        */
  57.   0000,                                 /* Letter (identifier)          */
  58.   0141, 0141, 0151, 0151, 0151,         /* ADD, SUB, MUL, DIV, MOD      */
  59.   0131, 0131, 0101, 0071, 0071,         /* ASL, ASR, AND,  OR, XOR      */
  60.   0111, 0111, 0121, 0121, 0121, 0121,   /*  EQ,  NE,  LT,  LE,  GE,  GT */
  61.   0061, 0051, 0041, 0041, 0031,         /* ANA, ORO, QUE, COL, CMA      */
  62. /*
  63.  * Unary op's follow
  64.  */
  65.   0160, 0160, 0160, 0160,               /* NEG, PLU, COM, NOT           */
  66.   0170, 0013, 0023,                     /* LPA, RPA, END                */
  67. };
  68. /*
  69.  * OP_QUE and OP_RPA have alternate precedences:
  70.  */
  71. #define OP_RPA_PREC     0013
  72. #define OP_QUE_PREC     0034
  73.  
  74. /*
  75.  * S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that
  76.  *      #if FOO != 0 && 10 / FOO ...
  77.  * doesn't generate an error message.  They are stored in optab.skip.
  78.  */
  79. #define S_ANDOR         2
  80. #define S_QUEST         1
  81.  
  82. typedef struct optab {
  83.     char        op;                     /* Operator                     */
  84.     char        prec;                   /* Its precedence               */
  85.     char        skip;                   /* Short-circuit: TRUE to skip  */
  86. } OPTAB;
  87. static int      evalue;                 /* Current value from evallex() */
  88.  
  89. #ifdef  nomacargs
  90. FILE_LOCAL int
  91. isbinary(op)
  92. register int    op;
  93. {
  94.         return (op >= FIRST_BINOP && op <= LAST_BINOP);
  95. }
  96.  
  97. FILE_LOCAL int
  98. isunary(op)
  99. register int    op;
  100. {
  101.         return (op >= FIRST_UNOP && op <= LAST_UNOP);
  102. }
  103. #else
  104. #define isbinary(op)    (op >= FIRST_BINOP && op <= LAST_BINOP)
  105. #define isunary(op)     (op >= FIRST_UNOP  && op <= LAST_UNOP)
  106. #endif
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124. /*
  125.  * The following definitions are used to specify basic variable sizes.
  126.  */
  127.  
  128. #ifndef S_CHAR
  129. #define S_CHAR          (sizeof (char))
  130. #endif
  131. #ifndef S_SINT
  132. #define S_SINT          (sizeof (short int))
  133. #endif
  134. #ifndef S_INT
  135. #define S_INT           (sizeof (int))
  136. #endif
  137. #ifndef S_LINT
  138. #define S_LINT          (sizeof (long int))
  139. #endif
  140. #ifndef S_FLOAT
  141. #define S_FLOAT         (sizeof (float))
  142. #endif
  143. #ifndef S_DOUBLE
  144. #define S_DOUBLE        (sizeof (double))
  145. #endif
  146. #ifndef S_PCHAR
  147. #define S_PCHAR         (sizeof (char *))
  148. #endif
  149. #ifndef S_PSINT
  150. #define S_PSINT         (sizeof (short int *))
  151. #endif
  152. #ifndef S_PINT
  153. #define S_PINT          (sizeof (int *))
  154. #endif
  155. #ifndef S_PLINT
  156. #define S_PLINT         (sizeof (long int *))
  157. #endif
  158. #ifndef S_PFLOAT
  159. #define S_PFLOAT        (sizeof (float *))
  160. #endif
  161. #ifndef S_PDOUBLE
  162. #define S_PDOUBLE       (sizeof (double *))
  163. #endif
  164. #ifndef S_PFPTR
  165. #define S_PFPTR         (sizeof (int (*)()))
  166. #endif
  167.  
  168.  
  169.  
  170.  
  171.  
  172. typedef struct types {
  173.     short       type;                   /* This is the bit if           */
  174.     char        *name;                  /* this is the token word       */
  175.     short       excluded;               /* but these aren't legal here  */
  176. } TYPES;
  177.  
  178. #define ANYSIGN         (T_SIGNED | T_UNSIGNED)
  179. #define ANYFLOAT        (T_FLOAT  | T_DOUBLE)
  180. #define ANYINT          (T_CHAR   | T_SHORT | T_INT | T_LONG)
  181.  
  182. static TYPES basic_types[] = {
  183.         T_CHAR,         "char",         ANYFLOAT | ANYINT,
  184.         T_INT,          "int",          ANYFLOAT | T_CHAR | T_INT,
  185.         T_FLOAT,        "float",        ANYFLOAT | ANYINT | ANYSIGN,
  186.         T_DOUBLE,       "double",       ANYFLOAT | ANYINT | ANYSIGN,
  187.         T_SHORT,        "short",        ANYFLOAT | ANYINT,
  188.         T_LONG,         "long",         ANYFLOAT | ANYINT,
  189.         T_SIGNED,       "signed",       ANYFLOAT | ANYINT | T_CHAR | T_INT,
  190.         T_UNSIGNED,     "unsigned",     ANYFLOAT | ANYINT | T_CHAR | T_INT,
  191.         0,              NULL,           0       /* Signal end           */
  192. };
  193.  
  194.  
  195. /*
  196.  * The order of this table is important -- it is also referenced by
  197.  * the command line processor to allow run-time overriding of the
  198.  * built-in size values.  The order must not be changed:
  199.  *      char, short, int, long, float, double (func pointer)
  200.  */
  201. SIZES size_table[] = {
  202.     { T_CHAR,   S_CHAR,         S_PCHAR         },      /* char         */
  203.     { T_SHORT,  S_SINT,         S_PSINT         },      /* short int    */
  204.     { T_INT,    S_INT,          S_PINT          },      /* int          */
  205.     { T_LONG,   S_LINT,         S_PLINT         },      /* long         */
  206.     { T_FLOAT,  S_FLOAT,        S_PFLOAT        },      /* float        */
  207.     { T_DOUBLE, S_DOUBLE,       S_PDOUBLE       },      /* double       */
  208.     { T_FPTR,   0,              S_PFPTR         },      /* int (*())    */
  209.     { 0,        0,              0               },      /* End of table */
  210. };
  211.  
  212.  
  213.  
  214.  
  215.  
  216.  
  217.  
  218.  
  219.  
  220. int
  221. eval()
  222. /*
  223.  * Evaluate an expression.  Straight-forward operator precedence.
  224.  * This is called from control() on encountering an #if statement.
  225.  * It calls the following routines:
  226.  * evallex      Lexical analyser -- returns the type and value of
  227.  *              the next input token.
  228.  * evaleval     Evaluate the current operator, given the values on
  229.  *              the value stack.  Returns a pointer to the (new)
  230.  *              value stack.
  231.  * For compatiblity with older cpp's, this return returns 1 (TRUE)
  232.  * if a syntax error is detected.
  233.  */
  234. {
  235.         register int    op;             /* Current operator             */
  236.         register int    *valp;          /* -> value vector              */
  237.         register OPTAB  *opp;           /* Operator stack               */
  238.         int             prec;           /* Op precedence                */
  239.         int             binop;          /* Set if binary op. needed     */
  240.         int             op1;            /* Operand from stack           */
  241.         int             skip;           /* For short-circuit testing    */
  242.         int             value[NEXP];    /* Value stack                  */
  243.         OPTAB           opstack[NEXP];  /* Operand stack                */
  244.         extern int      *evaleval();    /* Does actual evaluation       */
  245.  
  246.         valp = value;
  247.         opp = opstack;
  248.         opp->op = OP_END;               /* Mark bottom of stack         */
  249.         opp->prec = opdope[OP_END];     /* And its precedence           */
  250.         opp->skip = 0;                  /* Not skipping now             */
  251.         binop = 0;
  252. again:  ;
  253. #ifdef  DEBUG_EVAL
  254.         printf("In #if at again: skip = %d, binop = %d, line is: %s",
  255.             opp->skip, binop, infile->bptr);
  256. #endif
  257.         if ((op = evallex(opp->skip)) == OP_SUB && binop == 0)
  258.             op = OP_NEG;                        /* Unary minus          */
  259.         else if (op == OP_ADD && binop == 0)
  260.             op = OP_PLU;                        /* Unary plus           */
  261.         else if (op == OP_FAIL)
  262.             return (1);                         /* Error in evallex     */
  263. #ifdef  DEBUG_EVAL
  264.         printf("op = %s, opdope = %03o, binop = %d, skip = %d\n",
  265.             opname[op], opdope[op], binop, opp->skip);
  266. #endif
  267.         if (op == DIG) {                        /* Value?               */
  268.             if (binop != 0) {
  269.                 cerror("misplaced constant in #if", NULLST);
  270.                 return (1);
  271.             }
  272.             else if (valp >= &value[NEXP-1]) {
  273.                 cerror("#if value stack overflow", NULLST);
  274.                 return (1);
  275.             }
  276.             else {
  277. #ifdef  DEBUG_EVAL
  278.                 printf("pushing %d onto value stack[%d]\n",
  279.                     evalue, valp - value);
  280. #endif
  281.                 *valp++ = evalue;
  282.                 binop = 1;
  283.             }
  284.             goto again;
  285.         }
  286.         else if (op > OP_END) {
  287.             cerror("Illegal #if line", NULLST);
  288.             return (1);
  289.         }
  290.         prec = opdope[op];
  291.         if (binop != (prec & 1)) {
  292.             cerror("Operator %s in incorrect context", opname[op]);
  293.             return (1);
  294.         }
  295.         binop = (prec & 2) >> 1;
  296.         for (;;) {
  297. #ifdef  DEBUG_EVAL
  298.             printf("op %s, prec %d., stacked op %s, prec %d, skip %d\n",
  299.                 opname[op], prec, opname[opp->op], opp->prec, opp->skip);
  300. #endif
  301.             if (prec > opp->prec) {
  302.                 if (op == OP_LPA)
  303.                     prec = OP_RPA_PREC;
  304.                 else if (op == OP_QUE)
  305.                     prec = OP_QUE_PREC;
  306.                 op1 = opp->skip;                /* Save skip for test   */
  307.                 /*
  308.                  * Push operator onto op. stack.
  309.                  */
  310.                 opp++;
  311.                 if (opp >= &opstack[NEXP]) {
  312.                     cerror("expression stack overflow at op \"%s\"",
  313.                         opname[op]);
  314.                     return (1);
  315.                 }
  316.                 opp->op = (char)op;
  317.                 opp->prec = (char)prec;
  318.                 skip = (valp[-1] != 0);         /* Short-circuit tester */
  319.                 /*
  320.                  * Do the short-circuit stuff here.  Short-circuiting
  321.                  * stops automagically when operators are evaluated.
  322.                  */
  323.                 if ((op == OP_ANA && !skip)
  324.                  || (op == OP_ORO && skip))
  325.                     opp->skip = S_ANDOR;        /* And/or skip starts   */
  326.                 else if (op == OP_QUE)          /* Start of ?: operator */
  327.                     opp->skip = (char)(op1 & S_ANDOR) | ((!skip) ? S_QUEST : 0);
  328.                 else if (op == OP_COL) {        /* : inverts S_QUEST    */
  329.                     opp->skip = (char)(op1 & S_ANDOR)
  330.                               | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST);
  331.                 }
  332.                 else {                          /* Other ops leave      */
  333.                     opp->skip = (char)op1;      /*  skipping unchanged. */
  334.                 }
  335. #ifdef  DEBUG_EVAL
  336.                 printf("stacking %s, valp[-1] == %d at %s",
  337.                     opname[op], valp[-1], infile->bptr);
  338.                 dumpstack(opstack, opp, value, valp);
  339. #endif
  340.                 goto again;
  341.             }
  342.             /*
  343.              * Pop operator from op. stack and evaluate it.
  344.              * End of stack and '(' are specials.
  345.              */
  346.             skip = opp->skip;                   /* Remember skip value  */
  347.             switch ((op1 = opp->op)) {          /* Look at stacked op   */
  348.             case OP_END:                        /* Stack end marker     */
  349.                 if (op == OP_EOE)
  350.                     return (valp[-1]);          /* Finished ok.         */
  351.                 goto again;                     /* Read another op.     */
  352.  
  353.             case OP_LPA:                        /* ( on stack           */
  354.                 if (op != OP_RPA) {             /* Matches ) on input   */
  355.                     cerror("unbalanced paren's, op is \"%s\"", opname[op]);
  356.                     return (1);
  357.                 }
  358.                 opp--;                          /* Unstack it           */
  359.                 /* goto again;                  -- Fall through         */
  360.  
  361.             case OP_QUE:
  362.                 goto again;                     /* Evaluate true expr.  */
  363.  
  364.             case OP_COL:                        /* : on stack.          */
  365.                 opp--;                          /* Unstack :            */
  366.                 if (opp->op != OP_QUE) {        /* Matches ? on stack?  */
  367.                     cerror("Misplaced '?' or ':', previous operator is %s",
  368.                         opname[opp->op]);
  369.                     return (1);
  370.                 }
  371.                 /*
  372.                  * Evaluate op1.
  373.                  */
  374.             default:                            /* Others:              */
  375.                 opp--;                          /* Unstack the operator */
  376. #ifdef  DEBUG_EVAL
  377.                 printf("Stack before evaluation of %s\n", opname[op1]);
  378.                 dumpstack(opstack, opp, value, valp);
  379. #endif
  380.                 valp = evaleval(valp, op1, skip);
  381. #ifdef  DEBUG_EVAL
  382.                 printf("Stack after evaluation\n");
  383.                 dumpstack(opstack, opp, value, valp);
  384. #endif
  385.             }                                   /* op1 switch end       */
  386.         }                                       /* Stack unwind loop    */
  387. }
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409.  
  410.  
  411.  
  412. FILE_LOCAL int
  413. evallex(skip)
  414. int             skip;           /* TRUE if short-circuit evaluation     */
  415. /*
  416.  * Return next eval operator or value.  Called from eval().  It
  417.  * calls a special-purpose routines for 'char' strings and
  418.  * numeric values:
  419.  * evalchar     called to evaluate 'x'
  420.  * evalnum      called to evaluate numbers.
  421.  */
  422. {
  423.         register int    c, c1, t;
  424.  
  425. again:  do {                                    /* Collect the token    */
  426.             c = skipws();
  427.             if ((c = macroid(c)) == EOF_CHAR || c == '\n') {
  428.                 unget();
  429.                 return (OP_EOE);                /* End of expression    */
  430.             }
  431.         } while ((t = type[c]) == LET && catenate());
  432.         if (t == INV) {                         /* Total nonsense       */
  433.             if (!skip) {
  434.                 if (isascii(c) && isprint(c))
  435.                     cierror("illegal character '%c' in #if", c);
  436.                 else
  437.                     cierror("illegal character (%d decimal) in #if", c);
  438.             }
  439.             return (OP_FAIL);
  440.         }
  441.         else if (t == QUO) {                    /* ' or "               */
  442.             if (c == '\'') {                    /* Character constant   */
  443.                 evalue = evalchar(skip);        /* Somewhat messy       */
  444. #ifdef  DEBUG_EVAL
  445.                 printf("evalchar returns %d.\n", evalue);
  446. #endif
  447.                 return (DIG);                   /* Return a value       */
  448.             }
  449.             cerror("Can't use a string in an #if", NULLST);
  450.             return (OP_FAIL);
  451.         }
  452.         else if (t == LET) {                    /* ID must be a macro   */
  453.             if (streq(token, "defined")) {      /* Or defined name      */
  454.                 c1 = c = skipws();
  455.                 if (c == '(')                   /* Allow defined(name)  */
  456.                     c = skipws();
  457.                 if (type[c] == LET) {
  458.                     evalue = (lookid(c) != NULL);
  459.                     if (c1 != '('               /* Need to balance      */
  460.                      || skipws() == ')')        /* Did we balance?      */
  461.                         return (DIG);           /* Parsed ok            */
  462.                 }
  463.                 cerror("Bad #if ... defined() syntax", NULLST);
  464.                 return (OP_FAIL);
  465.             }
  466.             else if (streq(token, "sizeof"))    /* New sizeof hackery   */
  467.                 return (dosizeof());            /* Gets own routine     */
  468.             /*
  469.              * The Draft ANSI C Standard says that an undefined symbol
  470.              * in an #if has the value zero.  We are a bit pickier,
  471.              * warning except where the programmer was careful to write
  472.              *          #if defined(foo) ? foo : 0
  473.              */
  474.             if (!skip)
  475.                 cwarn("undefined symbol \"%s\" in #if, 0 used", token);
  476.             evalue = 0;
  477.             return (DIG);
  478.         }
  479.         else if (t == DIG) {                    /* Numbers are harder   */
  480.             evalue = evalnum(c);
  481. #ifdef  DEBUG_EVAL
  482.             printf("evalnum returns %d.\n", evalue);
  483. #endif
  484.         }
  485.         else if (strchr("!=<>&|\\", c) != NULL) {
  486.             /*
  487.              * Process a possible multi-byte lexeme.
  488.              */
  489.             c1 = cget();                        /* Peek at next char    */
  490.             switch (c) {
  491.             case '!':
  492.                 if (c1 == '=')
  493.                     return (OP_NE);
  494.                 break;
  495.  
  496.             case '=':
  497.                 if (c1 != '=') {                /* Can't say a=b in #if */
  498.                     unget();
  499.                     cerror("= not allowed in #if", NULLST);
  500.                     return (OP_FAIL);
  501.                 }
  502.                 return (OP_EQ);
  503.  
  504.             case '>':
  505.             case '<':
  506.                 if (c1 == c)
  507.                     return ((c == '<') ? OP_ASL : OP_ASR);
  508.                 else if (c1 == '=')
  509.                     return ((c == '<') ? OP_LE  : OP_GE);
  510.                 break;
  511.  
  512.             case '|':
  513.             case '&':
  514.                 if (c1 == c)
  515.                     return ((c == '|') ? OP_ORO : OP_ANA);
  516.                 break;
  517.  
  518.             case '\\':
  519.                 if (c1 == '\n')                 /* Multi-line if        */
  520.                     goto again;
  521.                 cerror("Unexpected \\ in #if", NULLST);
  522.                 return (OP_FAIL);
  523.             }
  524.             unget();
  525.         }
  526.         return (t);
  527. }
  528.  
  529.  
  530.  
  531.  
  532. FILE_LOCAL int
  533. dosizeof()
  534. /*
  535.  * Process the sizeof (basic type) operation in an #if string.
  536.  * Sets evalue to the size and returns
  537.  *      DIG             success
  538.  *      OP_FAIL         bad parse or something.
  539.  */
  540. {
  541.         register int    c;
  542.         register TYPES  *tp;
  543.         register SIZES  *sizp;
  544.         short           typecode;
  545.  
  546.         if ((c = skipws()) != '(')
  547.             goto nogood;
  548.         /*
  549.          * Scan off the tokens.
  550.          */
  551.         typecode = 0;
  552.         while ((c = skipws())) {
  553.             if ((c = macroid(c)) == EOF_CHAR || c == '\n')
  554.                 goto nogood;                    /* End of line is a bug */
  555.             else if (c == '(') {                /* thing (*)() func ptr */
  556.                 if (skipws() == '*'
  557.                  && skipws() == ')') {          /* We found (*)         */
  558.                     if (skipws() != '(')        /* Let () be optional   */
  559.                         unget();
  560.                     else if (skipws() != ')')
  561.                         goto nogood;
  562.                     typecode |= T_FPTR;         /* Function pointer     */
  563.                 }
  564.                 else {                          /* Junk is a bug        */
  565.                     goto nogood;
  566.                 }
  567.             }
  568.             else if (type[c] != LET)            /* Exit if not a type   */
  569.                 break;
  570.             else if (!catenate()) {             /* Maybe combine tokens */
  571.                 /*
  572.                  * Look for this unexpandable token in basic_types.
  573.                  */
  574.                 for (tp = basic_types; tp->name != NULLST; tp++) {
  575.                     if (streq(token, tp->name))
  576.                         break;
  577.                 }
  578.                 if (tp->name == NULLST) {
  579.                     cerror("#if sizeof, unknown type \"%s\"", token);
  580.                     return (OP_FAIL);
  581.                 }
  582.                 if ((typecode & tp->excluded) != 0) {
  583.                     cerror("#if sizeof: illegal type combination", NULLST);
  584.                     return (OP_FAIL);
  585.                 }
  586.                 typecode |= tp->type;           /* Or in the type bit   */
  587.             }
  588.         }
  589.         /*
  590.          * We are at the end of the type scan.  Chew off '*' if necessary.
  591.          */
  592.         if (c == '*') {
  593.             typecode |= T_PTR;
  594.             c = skipws();
  595.         }
  596.         if (c == ')') {                         /* Last syntax check    */
  597.             /*
  598.              * We assume that all function pointers are the same size:
  599.              *          sizeof (int (*)()) == sizeof (float (*)())
  600.              * We assume that signed and unsigned don't change the size:
  601.              *          sizeof (signed int) == (sizeof unsigned int)
  602.              */
  603.             if ((typecode & T_FPTR) != 0)       /* Function pointer     */
  604.                 typecode = T_FPTR | T_PTR;
  605.             else {                              /* Var or var * datum   */
  606.                 typecode &= ~(T_SIGNED | T_UNSIGNED);
  607.                 if ((typecode & (T_SHORT | T_LONG)) != 0)
  608.                     typecode &= ~T_INT;
  609.             }
  610.             if ((typecode & ~T_PTR) == 0) {
  611.                 cerror("#if sizeof() error, no type specified", NULLST);
  612.                 return (OP_FAIL);
  613.             }
  614.             /*
  615.              * Exactly one bit (and possibly T_PTR) may be set.
  616.              */
  617.             for (sizp = size_table; sizp->bits != 0; sizp++) {
  618.                 if ((typecode & ~T_PTR) == sizp->bits) {
  619.                     evalue = ((typecode & T_PTR) != 0)
  620.                         ? sizp->psize : sizp->size;
  621.                     return (DIG);
  622.                 }
  623.             }                                   /* We shouldn't fail    */
  624.             cierror("#if ... sizeof: bug, unknown type code 0x%x", typecode);
  625.             return (OP_FAIL);
  626.         }
  627.  
  628. nogood: unget();
  629.         cerror("#if ... sizeof() syntax error", NULLST);
  630.         return (OP_FAIL);
  631. }
  632.  
  633.  
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  
  641.  
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652. FILE_LOCAL int
  653. evalnum(c)
  654. register int    c;
  655. /*
  656.  * Expand number for #if lexical analysis.  Note: evalnum recognizes
  657.  * the unsigned suffix, but only returns a signed int value.
  658.  */
  659. {
  660.         register int    value;
  661.         register int    base;
  662.         register int    c1;
  663.  
  664.         if (c != '0')
  665.             base = 10;
  666.         else if ((c = cget()) == 'x' || c == 'X') {
  667.                 base = 16;
  668.                 c = cget();
  669.         }
  670.         else base = 8;
  671.         value = 0;
  672.         for (;;) {
  673.             c1 = c;
  674.             if (isascii(c) && isupper(c1))
  675.                 c1 = tolower(c1);
  676.             if (c1 >= 'a')
  677.                 c1 -= ('a' - 10);
  678.             else c1 -= '0';
  679.             if (c1 < 0 || c1 >= base)
  680.                 break;
  681.             value *= base;
  682.             value += c1;
  683.             c = cget();
  684.         }
  685.         if (c == 'u' || c == 'U')       /* Unsigned nonsense            */
  686.             c = cget();
  687.         unget();
  688.         return (value);
  689. }
  690.  
  691.  
  692.  
  693.  
  694.  
  695.  
  696.  
  697.  
  698.  
  699.  
  700. FILE_LOCAL int
  701. evalchar(skip)
  702. int             skip;           /* TRUE if short-circuit evaluation     */
  703. /*
  704.  * Get a character constant
  705.  */
  706. {
  707.         register int    c;
  708.         register int    value;
  709. #if BIG_ENDIAN
  710.         register int    count;
  711. #endif
  712.  
  713.         instring = TRUE;
  714.         if ((value = evalone()) == EOF_CHAR) {
  715.             switch (cget()) {
  716.             case '\'':                  /* Empty char constant          */
  717.                 cerror("Empty character constant", NULLST);
  718.                 return (0);
  719.  
  720.             /* case '\n':               -- Unterminated char constant   */
  721.             default:                    /* Junk or eof                  */
  722.                 cerror("Unterminated character constant", NULLST);
  723.                 return (0);
  724.             }
  725.         }
  726.         /*
  727.          * We warn on multi-byte constants and try to hack
  728.          * (big|little)endian machines.
  729.          */
  730. #if BIG_ENDIAN
  731.         count = 0;
  732. #endif
  733.         while ((c = evalone()) != EOF_CHAR) {
  734.             if (!skip)
  735.                 ciwarn("multi-byte constant '%c' isn't portable", c);
  736. #if BIG_ENDIAN
  737.             count += BITS_CHAR;
  738.             value += (c << count);
  739. #else
  740.             value <<= BITS_CHAR;
  741.             value += c;
  742. #endif
  743.         }
  744.         switch (cget()) {
  745.         case '\'':                      /* Normal char termination      */
  746.             break;
  747.  
  748.         /* case '\n':                   -- End of line seen             */
  749.         default:                        /* Junk or end of file seen     */
  750.             cerror("Unterminated multi-character constant", NULLST);
  751.             break;
  752.         }
  753.         instring = FALSE;
  754.         return (value);
  755. }
  756.  
  757.  
  758.  
  759.  
  760.  
  761.  
  762.  
  763.  
  764.  
  765.  
  766.  
  767.  
  768.  
  769.  
  770.  
  771.  
  772. FILE_LOCAL int
  773. evalone()
  774. /*
  775.  * Called from evalchar() above to get a single character with \ escapes.
  776.  * Returns the character or EOF_CHAR (on errors).
  777.  */
  778. {
  779.         register char   *cp;
  780.         register char   *digits;
  781.         register int    c;
  782.         register int    value;
  783.         register int    count;
  784.         extern char     *strchr();
  785.  
  786.         switch (c = cget()) {
  787.         default:
  788.             return (c);
  789.  
  790.         case '\n':
  791.         case '\'':
  792.             unget();
  793.             return (EOF_CHAR);                  /* Exits mult-char loop */
  794.  
  795.         case '\\':                              /* \ escape seen        */
  796.             break;
  797.         }
  798.         switch (c = cget()) {
  799.         case 'a':                               /* New in Standard      */
  800. #if ('a' == '\a' || '\a' == ALERT)
  801.             return (ALERT);                     /* Use predefined value */
  802. #else
  803.             return ('\a');                      /* Use compiler's value */
  804. #endif
  805.  
  806.         case 'b':
  807.             return ('\b');
  808.  
  809.         case 'f':
  810.             return ('\f');
  811.  
  812.         case 'n':
  813.             return ('\n');
  814.  
  815.         case 'r':
  816.             return ('\r');
  817.  
  818.         case 't':
  819.             return ('\t');
  820.  
  821.         case 'v':                               /* New in Standard      */
  822. #if ('v' == '\v' || '\v' == VT)
  823.             return (VT);                        /* Use predefined value */
  824. #else
  825.             return ('\v');                      /* Use compiler's value */
  826. #endif
  827.  
  828.         case 'x':                               /* '\xFF'               */
  829.             digits = "0123456789abcdef";
  830.             c = cget();
  831.             break;
  832.  
  833.         case '0': case '1': case '2': case '3':
  834.         case '4': case '5': case '6': case '7':
  835.             digits = "01234567";
  836.             break;
  837.  
  838.         default:
  839.             return (c);
  840.         }
  841.         value = 0;
  842.         for (count = 0; count < 3; ++count) {
  843.             if (c == EOF_CHAR)
  844.                 return (c);
  845.             if (isascii(c) && isupper(c))
  846.                 c = tolower(c);
  847.             if ((cp = strchr(digits, c)) == 0)
  848.                 break;
  849.             value = value * strlen(digits) + cp - digits;
  850.             c = cget();
  851.         }
  852.         unget();
  853.         if (count == 0)                         /* '\xnonsense'         */
  854.             return (EOF_CHAR);
  855.         return (value);
  856. }
  857.  
  858.  
  859.  
  860.  
  861.  
  862.  
  863.  
  864.  
  865.  
  866.  
  867.  
  868. FILE_LOCAL int *
  869. evaleval(valp, op, skip)
  870. register int    *valp;
  871. int             op;
  872. int             skip;           /* TRUE if short-circuit evaluation     */
  873. /*
  874.  * Apply the argument operator to the data on the value stack.
  875.  * One or two values are popped from the value stack and the result
  876.  * is pushed onto the value stack.
  877.  *
  878.  * OP_COL is a special case.
  879.  *
  880.  * evaleval() returns the new pointer to the top of the value stack.
  881.  */
  882. {
  883.         register int    v1, v2;
  884.  
  885.         if (isbinary(op))
  886.             v2 = *--valp;
  887.         v1 = *--valp;
  888. #ifdef  DEBUG_EVAL
  889.         printf("%s op %s", (isbinary(op)) ? "binary" : "unary",
  890.             opname[op]);
  891.         if (isbinary(op))
  892.             printf(", v2 = %d.", v2);
  893.         printf(", v1 = %d.\n", v1);
  894. #endif
  895.         switch (op) {
  896.         case OP_EOE:
  897.              break;
  898.  
  899.         case OP_ADD:
  900.             v1 += v2;
  901.             break;
  902.  
  903.         case OP_SUB:
  904.             v1 -= v2;
  905.             break;
  906.  
  907.         case OP_MUL:
  908.             v1 *= v2;
  909.             break;
  910.  
  911.         case OP_DIV:
  912.         case OP_MOD:
  913.             if (v2 == 0) {
  914.                 if (!skip) {
  915.                     cwarn("%s by zero in #if, zero result assumed",
  916.                         (op == OP_DIV) ? "divide" : "mod");
  917.                 }
  918.                 v1 = 0;
  919.             }
  920.             else if (op == OP_DIV)
  921.                 v1 /= v2;
  922.             else
  923.                 v1 %= v2;
  924.             break;
  925.  
  926.         case OP_ASL:
  927.             v1 <<= v2;
  928.             break;
  929.  
  930.         case OP_ASR:
  931.             v1 >>= v2;
  932.             break;
  933.  
  934.         case OP_AND:
  935.             v1 &= v2;
  936.             break;
  937.  
  938.         case OP_OR:
  939.             v1 |= v2;
  940.             break;
  941.  
  942.         case OP_XOR:
  943.             v1 ^= v2;
  944.             break;
  945.  
  946.         case OP_EQ:
  947.             v1 = (v1 == v2);
  948.             break;
  949.  
  950.         case OP_NE:
  951.             v1 = (v1 != v2);
  952.             break;
  953.  
  954.         case OP_LT:
  955.             v1 = (v1 < v2);
  956.             break;
  957.  
  958.         case OP_LE:
  959.             v1 = (v1 <= v2);
  960.             break;
  961.  
  962.         case OP_GE:
  963.             v1 = (v1 >= v2);
  964.             break;
  965.  
  966.         case OP_GT:
  967.             v1 = (v1 > v2);
  968.             break;
  969.  
  970.         case OP_ANA:
  971.             v1 = (v1 && v2);
  972.             break;
  973.  
  974.         case OP_ORO:
  975.             v1 = (v1 || v2);
  976.             break;
  977.  
  978.         case OP_COL:
  979.             /*
  980.              * v1 has the "true" value, v2 the "false" value.
  981.              * The top of the value stack has the test.
  982.              */
  983.             v1 = (*--valp) ? v1 : v2;
  984.             break;
  985.  
  986.         case OP_NEG:
  987.             v1 = (-v1);
  988.             break;
  989.  
  990.         case OP_PLU:
  991.             break;
  992.  
  993.         case OP_COM:
  994.             v1 = ~v1;
  995.             break;
  996.  
  997.         case OP_NOT:
  998.             v1 = !v1;
  999.             break;
  1000.  
  1001.         default:
  1002.             cierror("#if bug, operand = %d.", op);
  1003.             v1 = 0;
  1004.         }
  1005.         *valp++ = v1;
  1006.         return (valp);
  1007. }
  1008.  
  1009.  
  1010.  
  1011.  
  1012. #ifdef  DEBUG_EVAL
  1013. dumpstack(opstack, opp, value, valp)
  1014. OPTAB           opstack[NEXP];  /* Operand stack                */
  1015. register OPTAB  *opp;           /* Operator stack               */
  1016. int             value[NEXP];    /* Value stack                  */
  1017. register int    *valp;          /* -> value vector              */
  1018. {
  1019.         printf("index op prec skip name -- op stack at %s", infile->bptr);
  1020.         while (opp > opstack) {
  1021.             printf(" [%2d] %2d  %03o    %d %s\n", opp - opstack,
  1022.                 opp->op, opp->prec, opp->skip, opname[opp->op]);
  1023.             opp--;
  1024.         }
  1025.         while (--valp >= value) {
  1026.             printf("value[%d] = %d\n", (valp - value), *valp);
  1027.         }
  1028. }
  1029. #endif
  1030.  
  1031.  
  1032.